package com.springBoot.springBootSysCore.common.third.pay;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;

import com.springBoot.springBootSysCore.common.third.pay.wechat.message.Property;
import com.springBoot.springBootSysCore.common.third.pay.wechat.message.WxMessage;
import com.springBoot.springBootSysCore.common.third.pay.wechat.wechatPay.AssistUtil;
import com.springBoot.springBootSysCore.common.third.pay.wechat.wechatPay.Wechat;
import com.springBoot.springBootSysCore.common.utils.DateUtils;
import com.springBoot.springBootSysCore.common.utils.IdGen;
import com.springBoot.springBootSysCore.common.utils.http.HttpsGet;
import com.springBoot.springBootSysCore.common.utils.http.HttpsPost;

import net.sf.json.JSONObject;

public class WechatUtil {
	 @Value("${projectPath}")
		private static String PROJECT_PATH;
	/**
	 * 微信支付[app支付]
	 * @param ip		客户端IP
	 * @param number	订单号
	 * @param body		展示内容
	 * @param money		订单金额
	 * @param notify_url		回调通知接口
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> wechatAppPay(String ip,String number,String body,String money,String notify_url) throws Exception{
		return Wechat.wechatAppPay(ip, number, body, money,PROJECT_PATH+"/"+notify_url);
	}
	/**
	 * 微信支付[公众号支付]
	 * @param ip		客户端IP
	 * @param opendId	公众号下的opendId
	 * @param number	订单号
	 * @param body		展示内容
	 * @param money		订单金额
	 * @param notify_url		回调通知接口
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> wechatJsApiPay(String ip,String opendId,String number,String body,String money,String notify_url) throws Exception{
		return Wechat.wechatJsApiPay(ip, opendId, number, body, money, PROJECT_PATH+"/"+notify_url);
	}
	
	
	/**
	 * 微信退款
	 * @param payWay	支付方式:app支付：app/公众号支付:js
	 * @param trade_no	交易单号
	 * @param countMoney订单总金额
	 * @param money		退款金额
	 * @param batch_no	批次号
	 * @param path		证书地址
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> wechatRefund(String payWay,String trade_no,String countMoney,String money,String batch_no,String path) throws Exception{
		String appId = Wechat.APP_ID,mchId = Wechat.MCH_ID,apiKey = Wechat.API_KEY;
		if("js".equals(payWay)){
			appId = Wechat.JS_APP_ID;
			mchId = Wechat.JS_MCH_ID;
			apiKey = Wechat.JS_API_KEY;
		}
		
		return Wechat.refund(appId, mchId, apiKey, trade_no,countMoney,money,batch_no, path);
	}
	
	
	/**
	 * 得到微信回调传来的参数
	 * @param requestParams
	 * @return
	 * @throws IOException 
	 */
	public static Map<String,String> getWechatParams(HttpServletRequest request) throws Exception{
		Map<String,String> params = new HashMap<String,String>();
		
		String inputLine;  
		String notityXml = ""; 
		while ((inputLine = request.getReader().readLine()) != null) {  
            notityXml += inputLine;  
        }  
		request.getReader().close();  
		if(StringUtils.isNotEmpty(notityXml)){
			params = AssistUtil.parseXml(notityXml);
		}
		
		System.out.println("微信回调函数："+notityXml);
		return params;
	}
	
	/**
	 * 验证是否是微信发出的请求
	 * @param params
	 * @return
	 */
	public static boolean wechatVerify(Map<String,String> params){
		String sign = AssistUtil.getSignCommon("UTF-8", params, Wechat.API_KEY);
		return sign.equals(params.get("sign"));
	}
	
	/**
	 * 给微信回调返回状态
	 * @param response
	 * @param isOk
	 * @throws Exception 
	 */
	public static void returnState(HttpServletResponse response,boolean isOk) throws Exception{
		if(isOk){
			response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
		}else{
			response.getWriter().write("<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[DEFEATED]]></return_msg></xml>");
		}
	}
	
	
	/*****************************微信公众号***************************/
	/**
	 * 根据CODE获取相应信息
	 * @param code
	 * @return
	 * { "access_token":"ACCESS_TOKEN",  	网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
		 "expires_in":7200,   				access_token接口调用凭证超时时间，单位（秒）
		 "refresh_token":"REFRESH_TOKEN",   用户刷新access_token
		 "openid":"OPENID",   				用户唯一标识
		 "scope":"SCOPE" 					用户授权的作用域，使用逗号（,）分隔
		}
		
		{"errcode":40029,"errmsg":"invalid code"}	请求错误
	 */
	public static String getWxInfoByCode(String code){
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+Wechat.JS_APP_ID+"&secret="+Wechat.JS_APPS_SECRET
				+"&code="+code+"&grant_type=authorization_code";
		String backData=HttpsGet.doGet(url);
		if(backData.contains("errcode")){//请求错误
			return null;
		}
		return backData;
	}
   
	/**
	 * 通过参数获取微信用户信息
	 * @param infoJson
	 * @return
	 */
	public static String getWechatUserInfo(String infoJson){
		JSONObject jo = JSONObject.fromObject(infoJson);
		if("snsapi_userinfo".equals(jo.getString("scope"))){
			String userInfoJSON = HttpsGet.doGet("https://api.weixin.qq.com/sns/userinfo?access_token="+jo.getString("access_token")+"&openid="+jo.getString("openid")+"&lang=zh_CN");
			System.out.println("用户信息："+userInfoJSON);
			return userInfoJSON;
		}
		return null;
	}
	
	/**
	* 获取acess_token 
    * 有效期7200秒,需缓存
    * @return
	* @throws Exception 
    */
	public static String getAccessToken(HttpServletRequest request) throws Exception{
			int differTime = 7200;
			HttpSession httpSession = null;
			if(request != null){
				httpSession = request.getSession();
				String oldDate = (String) httpSession.getAttribute(httpSession.getId()+"acess_token_time");
				if(oldDate != null){
					differTime =  DateUtils.getBetweenSecond(oldDate, DateUtils.formatDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"));
				}
			}
			
			String accessToken = "";
			if(differTime < 7200){
				accessToken = (String) httpSession.getAttribute(httpSession.getId()+"acess_token");
			}else{
				String url ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+Wechat.JS_APP_ID+"&secret="+Wechat.JS_APPS_SECRET+"";
		        String backData=HttpsGet.doGet(url);
		        System.out.println("***********************"+backData+"**************************");
		        accessToken = JSONObject.fromObject(backData).get("access_token").toString(); 
		        if(httpSession != null){
		        	httpSession.setAttribute(httpSession.getId()+"acess_token",accessToken);
			        httpSession.setAttribute(httpSession.getId()+"acess_token_time",DateUtils.formatDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"));
		        }
			}
          return accessToken;
   }
	
	/***
     * 获取JSSDK权限验证配置信息
     * @return
     * @throws Exception 
     */
   public static Map<String, String> getJSApiTicket(HttpServletRequest request,String pageUrl) throws Exception{ 
	   //获取token
       String acess_token= getAccessToken(request);
		
		int differTime = 7200;
		HttpSession httpSession = null;
		if(request != null){
			httpSession = request.getSession();
			String oldDate = (String) httpSession.getAttribute(httpSession.getId()+"jsapi_ticket_time");
			if(oldDate != null){
				differTime =  DateUtils.getBetweenSecond(oldDate, DateUtils.formatDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"));
			}
		}
		
		String jsapi_ticket = "";
	   if(differTime < 7200){
    	   jsapi_ticket = (String) httpSession.getAttribute(httpSession.getId()+"jsapi_ticket");//有效期7200秒,需缓存
       }else{
    	   String urlStr = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+acess_token+"&type=jsapi";  
    	   String backData=HttpsGet.doGet(urlStr);  
    	   jsapi_ticket = (String) JSONObject.fromObject(backData).get("ticket");  
    	   
    	   if(httpSession != null){
    		   httpSession.setAttribute(httpSession.getId()+"jsapi_ticket",jsapi_ticket);
        	   httpSession.setAttribute(httpSession.getId()+"jsapi_ticket_time",DateUtils.formatDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"));
    	   }
       }
		
       Map<String, String> ret = new HashMap<String, String>();
       
       String nonce_str = IdGen.get32UUID();
       String timestamp = Long.toString(System.currentTimeMillis() / 1000);
       String string1;
       String signature = "";
		
		//注意这里参数名必须全部小写，且必须有序
		string1 = "jsapi_ticket=" + jsapi_ticket +
		  "&noncestr=" + nonce_str +
		  "&timestamp=" + timestamp +
		  "&url=" + pageUrl;
		System.out.println(string1);
		
		try{
		    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
		    crypt.reset();
			crypt.update(string1.getBytes("UTF-8"));
		    signature = byteToHex(crypt.digest());
		}catch (NoSuchAlgorithmException e){
		    e.printStackTrace();
		}catch (UnsupportedEncodingException e){
		    e.printStackTrace();
		}
		
		ret.put("appId", Wechat.JS_APP_ID);
		ret.put("nonceStr", nonce_str);
		ret.put("timestamp", timestamp);
		ret.put("signature", signature);
		
		return  ret;  
   } 
  
  private static String byteToHex(final byte[] hash) {
      Formatter formatter = new Formatter();
      for (byte b : hash)
      {
          formatter.format("%02x", b);
      }
      String result = formatter.toString();
      formatter.close();
      return result;
  }
  
   
   /**
    * 给微信发布模版消息
    * @param wxMessage
    * @return
    */
	public static boolean sendTemplateMessage(String accessToken,WxMessage wxMessage){
	  	JSONObject obj = JSONObject.fromObject(wxMessage);
	  	System.out.println(obj.toString());
		try {
			String result = HttpsPost.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+accessToken, 
					obj.toString(), "UTF-8");
			return result.contains("ok");
		} catch (Exception e) {
			e.printStackTrace();
		}
	  	return false;
  	}
	
	/**
	 * 发送充值通知[例子]
	 * @param openId	微信用户的openId
	 * @param account	充值账号
	 * @param amount	充值金额
	 * @return
	 */
	public static boolean sendRechargeInform(String accessToken,String openId,String account,String amount){
		WxMessage wm = new WxMessage();
		wm.setTouser(openId);
		wm.setTemplate_id("xQvfmVvz10I7eFfCwfQoAoFZ8Imgm90f0IRuow80dXM");
		Map<String,Property> data  = new HashMap<String, Property>();
		data.put("first", new Property("您好，您已成功进行融乐E家余额充值!"));
		data.put("accountType", new Property("充值账号"));
		data.put("account", new Property(account));
		data.put("amount", new Property(amount));
		data.put("result", new Property("充值成功"));
		data.put("remark", new Property("感谢使用融乐E家!"));
		wm.setData(data);
		
		return sendTemplateMessage(accessToken,wm);
	}
	

}
